Conversation
- pin es-module-lexer to the template-worker's major (1.x) to keep parser parity - reserve multipart/config overhead headroom under the upload limit - smoke-load the bundle with stubbed externals and verify the default export is a React component - reject builds emitting more than one output file - normalize scaffold package names and surface non-ENOENT init errors - print esbuild diagnostics once and always exit explicitly
There was a problem hiding this comment.
Pull request overview
Adds a new workspace package @fishjam-cloud/composition-cli, providing a CLI to scaffold composition template projects and build/validate template bundles locally (to fail fast with actionable contract violations). This fits into the repo as tooling around the existing @fishjam-cloud/composition template contract and build pipeline.
Changes:
- Introduces
composition-cli init(scaffold template project) andcomposition-cli build(bundle + validate + smoke-load). - Adds contract/manifest definitions plus validation/smoke-check logic, with Vitest coverage for init/build/validation.
- Updates CI to run unit tests for
compositionandcomposition-cli, and updates release workflow to publish the new package.
Reviewed changes
Copilot reviewed 18 out of 19 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| yarn.lock | Adds new workspace + dependencies (esbuild/tsup/commander/vitest, etc.) needed for the CLI. |
| packages/composition-cli/tsconfig.json | TypeScript config for the new CLI package. |
| packages/composition-cli/tests/validate.test.ts | Unit tests for import/ESM contract validation. |
| packages/composition-cli/tests/init.test.ts | Unit tests for project scaffolding behavior. |
| packages/composition-cli/tests/build.test.ts | Unit tests for bundling + validation + size limits + smoke checks. |
| packages/composition-cli/src/validate.ts | Implements static validation of bundle imports/exports. |
| packages/composition-cli/src/smoke.ts | Implements smoke-load validation (load bundle and verify default export is a component). |
| packages/composition-cli/src/manifests/v1.ts | Defines the v1 platform contract (allowed imports, build target, size limit, scaffold deps). |
| packages/composition-cli/src/manifests/types.ts | Defines the manifest TypeScript type. |
| packages/composition-cli/src/manifests/index.ts | Manifest registry + getManifest() lookup with error on unknown target. |
| packages/composition-cli/src/init.ts | Implements init scaffolding (package.json/tsconfig/App.tsx/.gitignore). |
| packages/composition-cli/src/index.ts | CLI entrypoint wiring (build and init) via commander. |
| packages/composition-cli/src/build.ts | Implements esbuild bundling + validation + size checking + outfile write. |
| packages/composition-cli/README.md | Package documentation for install/usage. |
| packages/composition-cli/package.json | New package metadata, scripts, dependencies, bin entry. |
| packages/composition-cli/LICENSE | Apache-2.0 license text for the new package. |
| packages/composition-cli/eslint.config.mjs | ESLint config for the new package. |
| .github/workflows/static.yaml | Runs workspace unit tests in CI. |
| .github/workflows/release.yaml | Adds composition-cli to the publish matrix. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- type lexer results explicitly in validateBundle - surface smoke-build failures as validation violations - clamp bundle budget at zero for tiny upload limits - fix package description typo and add license field
czerwiukk
left a comment
There was a problem hiding this comment.
Is js-server-sdk the right place for the CLI? I feel like foundry is a
| - name: Check typing | ||
| run: yarn typecheck | ||
|
|
||
| - name: Unit tests |
There was a problem hiding this comment.
nitpick: it may be wise to only run CLI tests only if there are changes in cli directory, as it has no dependency on the rest of the repo
| jsxImportSource: 'react', | ||
| }, | ||
| scaffoldDevDependencies: { | ||
| '@fishjam-cloud/composition': '0.29.0-rc.2', |
There was a problem hiding this comment.
suggestion:
i think we want to allow all versions starting from 0.29.0
| '@fishjam-cloud/composition': '0.29.0-rc.2', | |
| '@fishjam-cloud/composition': '^0.29.0', |
| import { smokeLoadBundle } from './smoke'; | ||
| import { validateBundle } from './validate'; | ||
|
|
||
| const UPLOAD_OVERHEAD_RESERVE_BYTES = 50_000; |
There was a problem hiding this comment.
suggestion: this should probably also land in the manifest
| const encoded = Buffer.from(result.outputFiles[0].contents).toString('base64'); | ||
| let mod: { default?: unknown }; | ||
| try { | ||
| mod = (await import(`data:text/javascript;base64,${encoded}`)) as { default?: unknown }; |
There was a problem hiding this comment.
suggestion: this runs the top level user code with full privileges and no timeout. a top level while(true) will hang the whole process. we could say it's user's concern, or just run it in on worker thread with a timeout?
Summary
New package
@fishjam-cloud/composition-cli— a CLI that scaffolds and builds composition template bundlescomposition-cli init <dir>— scaffolds a template project (package.json with supported dependency versions, tsconfig, hello-worldsrc/App.tsx)composition-cli build [entry]— bundles the template and validates it locally against the platform contract, so contract violations fail at build time with named reasons instead of at upload with an opaqueInvalid user bundleFor now validation uses manifest v1 that is compatible with foundry template worker environment, but we're planning to add version management in templates API so the validation step may possibly change later